home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Practical Algorithms for Image Analysis
/
Practical Algorithms for Image Analysis.iso
/
TARFILE.GZ
/
tarfile
/
ch_4.3
/
contour
/
contour.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-11
|
10KB
|
345 lines
/*
* contour.c
*
* Practical Algorithms for Image Analysis
*
* Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
*/
/* CONTOUR: program determines contour boundaries for binary image
* usage: contour infile.img outfile.img
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tiffimage.h" /* picfile info on images */
#include "images.h"
extern void print_sos_lic ();
#define ON 0 /* binarization values */
#define OFF 255
#define ONM1 1
#define CONTOUR 32 /* value of contour pixel */
#define CENTROID 31 /* value of centroid location pixel */
#define MAX_CONTOUR 10000 /* maximum length of contour */
#define DISPLAY_FLAG_DFLT 0 /* =0 contours; =1 centroids; =2 both */
#define SQUARE(IMG,X,Y) IMG[Y][X] = ONM1, IMG[Y-1][X-1] = ONM1,\
IMG[Y-1][X] = ONM1, IMG[Y-1][X+1] = ONM1,\
IMG[Y][X+1] = ONM1, IMG[Y+1][X+1] = ONM1,\
IMG[Y+1][X] = ONM1, IMG[Y+1][X-1] = ONM1,\
IMG[Y][X-1] = ONM1
int nextcntr (unsigned char **, long *, long *, long *);
long usage (short);
long input (int, char **, long *, short *, short *);
main (argc, argv)
int argc;
char *argv[];
{
Image *imgIO; /* I/O image structure */
unsigned char **image; /* input/output image */
long height, width; /* size of I/O images */
long xEndM1, yEndM1; /* end of rows/columns minus one */
struct cntr { /* structure for each contour pt */
long x, y; /* location */
long iDirn; /* chain code direction */
long curve; /* local curvature */
} *cntr;
long maxContour; /* max. contour length (for memory alloc.) */
short displayFlag; /* =0 contours; =1 centroids; =2 both */
short printFlag; /* =1 print contour info; =0 don't */
long nContour; /* number of contours */
long lContour; /* length of contour */
long maxLContour; /* max. length of contour */
long lContourSum; /* sum of contour lengths */
double xCentroid, yCentroid; /* x,y centroid location for contour */
long xStart, yStart; /* starting pixels of contour */
long iDirn; /* direction coming into contour */
long x, y;
long temp;
/* user input */
if (input (argc, argv, &maxContour, &displayFlag, &printFlag) < 0)
return (-1);
imgIO = ImageIn (argv[1]);
image = imgIO->img;
height = ImageGetHeight (imgIO);
width = ImageGetWidth (imgIO);
printf ("image size is %dx%d\n", width, height);
/* allocate contour memory */
if ((cntr = (struct cntr *) calloc (maxContour, sizeof (struct cntr)))
== NULL) {
printf ("CONTOUR: not enough memory -- sorry.\n");
return (-1);
}
/* determine contours */
yEndM1 = height - 1;
xEndM1 = width - 1;
nContour = 0;
maxLContour = 0;
lContourSum = 0;
for (y = 1; y < yEndM1; y++) {
for (x = 1; x < xEndM1; x++) {
/* when find ON-pixel, trace contour */
if (image[y][x] == ON && image[y][x - 1] == OFF) {
nContour++;
iDirn = 2;
cntr[0].x = xStart = x;
cntr[0].y = yStart = y;
xCentroid = (double) x;
yCentroid = (double) y;
cntr[0].iDirn = iDirn;
cntr[0].curve = 0;
lContour = 1;
do {
image[y][x] = CONTOUR;
nextcntr (image, &x, &y, &iDirn);
cntr[lContour].x = x;
cntr[lContour].y = y;
cntr[lContour].iDirn = iDirn;
xCentroid += (double) x;
yCentroid += (double) y;
temp = iDirn - cntr[lContour - 1].iDirn;
if (temp > 4)
temp -= 8;
else if (temp < -4)
temp += 8;
cntr[lContour].curve = temp;
lContour++;
if (lContour == MAX_CONTOUR) {
printf ("Nuts -- maximum contour length reached = %d\n", lContour);
return (-1);
}
} while (!(x == xStart && y == yStart));
if (lContour > maxLContour)
maxLContour = lContour;
xCentroid = xCentroid / (double) lContour;
yCentroid = yCentroid / (double) lContour;
lContourSum += lContour;
if (displayFlag > 0)
image[(long) (yCentroid + 0.5)][(long) (xCentroid + 0.5)] = CENTROID;
if (printFlag != 0)
printf ("contour %ld: length = %ld, centroid = (%5.2f,%5.2f)\n",
nContour - 1, lContour, xCentroid, yCentroid);
}
}
}
switch (displayFlag) {
case 0:
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
image[y][x] = (image[y][x] == CONTOUR) ? ON : OFF;
break;
case 1:
for (y = 0; y < height; y++)
for (x = 0; x < width; x++) {
if (image[y][x] == CENTROID)
SQUARE (image, x, y);
else if (image[y][x] == ONM1);
else
image[y][x] = OFF;
}
break;
case 2:
for (y = 0; y < height; y++)
for (x = 0; x < width; x++) {
if (image[y][x] == CENTROID)
SQUARE (image, x, y);
else if (image[y][x] == CONTOUR)
image[y][x] = ON;
else if (image[y][x] == ONM1);
else
image[y][x] = OFF;
}
break;
default:
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
image[y][x] = (image[y][x] == CONTOUR) ? ONM1 : OFF;
}
if (nContour == 0)
printf ("no image regions\n");
else
printf ("no. contours = %d, max length = %d, avg. length = %d\n",
nContour, maxLContour, lContourSum / nContour);
ImageOut (argv[2], imgIO);
return (0);
}
/* NEXTCNTR: function examines neighborhood for next contour pixel
*/
int
nextcntr (image, x, y, iDirn)
unsigned char **image;
long *x, *y; /* temporary x and y storage for trace */
long *iDirn; /* direction from last pixel on contour */
{
long ring[16]; /* neighborhood ring of pixels */
long i, j;
/* find neighborhood ring of pixels */
ring[0] = ring[8] = image[*y - 1][*x];
ring[1] = ring[9] = image[*y - 1][*x + 1];
ring[2] = ring[10] = image[*y][*x + 1];
ring[3] = ring[11] = image[*y + 1][*x + 1];
ring[4] = ring[12] = image[*y + 1][*x];
ring[5] = ring[13] = image[*y + 1][*x - 1];
ring[6] = ring[14] = image[*y][*x - 1];
ring[7] = ring[15] = image[*y - 1][*x - 1];
i = (*iDirn + 4 + 1) % 8;
for (j = 0; j < 8; j++, i++)
if (ring[i] != OFF && ring[i - 1] == OFF)
break;
if (j == 8)
return (0); /* isolated pixel */
*iDirn = i % 8;
switch (i) {
case 1:
case 9:
*x = *x + 1;
*y = *y - 1;
break;
case 2:
case 10:
*x = *x + 1;
break;
case 3:
case 11:
*x = *x + 1;
*y = *y + 1;
break;
case 4:
case 12:
*y = *y + 1;
break;
case 5:
case 13:
*x = *x - 1;
*y = *y + 1;
break;
case 6:
case 14:
*x = *x - 1;
break;
case 7:
case 15:
*x = *x - 1;
*y = *y - 1;
break;
case 8:
case 0:
*y = *y - 1;
break;
default:;
}
return (0);
}
/* USAGE: function gives instructions on usage of program
* usage: usage (flag)
* When flag is 1, the long message is given, 0 gives short.
*/
long
usage (flag)
short flag; /* flag =1 for long message; =0 for short message */
{
/* print short usage message or long */
printf ("USAGE: contour inimg outimg [-d DISPLAY] [-p] \n");
printf (" [-m MAX_CONTOUR_LENGTH] [-L]\n");
if (flag == 0)
return (-1);
printf ("\ncontour identifies contours, or boundaries, of regions\n");
printf ("in a binary image, and determines features of the regions.\n\n");
printf ("ARGUMENTS:\n");
printf (" inimg: input image filename (TIF)\n");
printf (" outimg: output image filename (TIF)\n\n");
printf ("OPTIONS:\n");
printf (" -d DISPLAY: display just centroids (1), or both\n");
printf (" contours and centroids (2);\n");
printf (" default displays just contours.\n");
printf (" -p: PRINT DATA FLAG if set, prints contour\n");
printf (" number, length, and centroid data.\n");
printf (" -m MAX_CONTOUR_LENGTH: maximum contour length in pixel\n");
printf (" connections. (Default = %d)\n", MAX_CONTOUR);
printf (" -L: print Software License for this module\n");
return (-1);
}
/* INPUT: function reads input parameters
* usage: input (argc, argv, &maxContour, &displayFlag)
*/
#define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
long
input (argc, argv, maxContour, displayFlag, printFlag)
int argc;
char *argv[];
long *maxContour; /* maximum contour length (for memory alloc) */
short *displayFlag; /* =0 contours; =1 centroids; =2 both */
short *printFlag; /* =1, print contour data; =0 don't */
{
long n;
if (argc == 1)
USAGE_EXIT (1);
if (argc == 2)
USAGE_EXIT (0);
*maxContour = MAX_CONTOUR;
*displayFlag = DISPLAY_FLAG_DFLT;
*printFlag = 0;
for (n = 3; n < argc; n++) {
if (strcmp (argv[n], "-m") == 0) {
if (++n == argc || argv[n][0] == '-')
USAGE_EXIT (0);
*maxContour = atol (argv[n]);
}
else if (strcmp (argv[n], "-d") == 0) {
if (++n == argc || argv[n][0] == '-')
USAGE_EXIT (0);
*displayFlag = (short) atol (argv[n]);
}
else if (strcmp (argv[n], "-p") == 0) {
*printFlag = 1;
}
else if (strcmp (argv[n], "-L") == 0) {
print_sos_lic ();
exit (0);
}
else
USAGE_EXIT (0);
}
return (0);
}